/*
 简单的字符设备驱动，手动静态分配设备号，手动创建设备节点
 */
#include<linux/module.h>
#include<linux/moduleparam.h>
#include<linux/cdev.h>
#include<linux/fs.h>
#include<linux/wait.h>
#include<linux/poll.h>
#include<linux/sched.h>
#include<mach/gpio.h>
#include<mach/regs-gpio.h>
#include<plat/gpio-cfg.h>

#include<linux/slab.h>

#define DEVICE_NAME "leds"

static long ledsIoctl(struct file *,unsigned int,unsigned long);
static int ledsOpen(struct inode *,struct file *);

static int led_gpios[]=
{
    S5PV210_GPJ2(0),
	S5PV210_GPJ2(1),
	S5PV210_GPJ2(2),
	S5PV210_GPJ2(3),
};

#define LED_NUM ARRAY_SIZE(led_gpios)
#define OK (0)
#define ERROR (-1)

struct cdev *gDev;
dev_t devNum;
unsigned int subDevNum = 1;
int reg_major = 232;
int reg_minor = 0;
char *buffer;
int flag=0;
char kbuf[4]={0};

static struct file_operations led_fops = {
	.owner 				= THIS_MODULE,
	.unlocked_ioctl 	= ledsIoctl,
	.open               = ledsOpen,
	
};

static int ledsOpen(struct inode *p,struct file *f)
{
	printk(KERN_EMERG"ledsOpen\r\n");
	return 0;
}


static long ledsIoctl(struct file *file,unsigned int cmd,unsigned long arg)
{
	printk(KERN_EMERG"ledsIoctl\r\n");
	switch(cmd)
	{
		case 0:
		case 1:
		if(arg > LED_NUM) return EINVAL;
		gpio_set_value(led_gpios[arg],!cmd);
		break;
		default:return -EINVAL;

	}
	return 0;
}


int charDrvInit(void)
{
    int i;
	devNum = MKDEV(reg_major,reg_minor);
	printk(KERN_EMERG"devNum is %d\r\n",devNum);
	if(OK == register_chrdev_region(devNum,subDevNum,DEVICE_NAME))
	{
		printk(KERN_EMERG"register_chrdev_region ok\r\n");
	}
	else
	{
		printk(KERN_EMERG"register_chrdev_region error\r\n");
		return -ERROR;
	}

	printk(KERN_EMERG"devNum is %d\r\n",devNum);
	gDev = cdev_alloc();
	gDev->ops = &led_fops;
	cdev_add(gDev,devNum,3);
	
	for(i=0;i<LED_NUM;i++)
	{
		s3c_gpio_cfgpin(led_gpios[i], S3C_GPIO_OUTPUT);
		gpio_set_value(led_gpios[i],1);
	}
	return 0;
}


void __exit charDrvExit(void)
{
	int i;
	for(i=0;i<LED_NUM;i++)
	{
		gpio_free(led_gpios[i]);
	}
	cdev_del(gDev);
	unregister_chrdev_region(devNum,subDevNum);
	return;
}


module_init(charDrvInit);//insmod ***.ko
module_exit(charDrvExit);//rmmod ***.ko
MODULE_LICENSE("GPL");


